#ifndef FUNCTIONS_H
#define	FUNCTIONS_H

#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>

#include "user_functions.h"

#include "big_int.h"

namespace functions
{
   struct big_int_from_str_i
   {
      template<typename A>
      struct result
      {
         typedef big_int type;
      };

      template<typename A>
      big_int operator()(A a) const
      {
         return big_int(a);
      }
   };

   struct pow_i
   {
      template<typename A, typename B>
      struct result
      {
         typedef big_int type;
      };

      template<typename A, typename B>
      big_int power(A a, B b) const
      {
         if (b < big_int(0))
         {
            return big_int(0);
         }
         if (b == big_int(0))
         {
            return big_int(1);
         }
         
         A tmp = power(a, b / big_int(2));
         
         if (b % big_int(2) == big_int(0))
         {
            return tmp * tmp;
         }
         else
         {
            return tmp * tmp * a;
         }
      }
      
      template<typename A, typename B>
      big_int operator()(A a, B b) const
      {
         return power(a, b);
      }
   };
   
   struct user_function_i
   {
      template<typename A, typename B>
      struct result
      {
         typedef B type;
      };
      
      template<typename A, typename B>
      B operator()(A a, B b) const
      {
         return (*(get_function()[a]))(b);
      }
   };
}

boost::phoenix::function<functions::big_int_from_str_i>& big_int_from_str();
boost::phoenix::function<functions::pow_i>& pow();
boost::phoenix::function<functions::user_function_i>& user_function();

#endif

